# 4.7 人脸识别

## 4.7.1 算法简介

![18](./media/18.png)

判断图像中是否有人脸及识别人脸，用户可通过功能按键训练存储或删除人脸数据，Sengo2可以存储15张人脸数据。

-----------------

## 4.7.2 人脸分类标签

Sengo2定义了17个人脸的分类标签：

| 分类标签 |  含义  | 分类标签 |        含义        |
| :------: | :----: | :------: | :----------------: |
|    0     | 新人脸 |   1-15   | 存储的人脸分类编号 |
|   200    | 戴口罩 |          |                    |

新人脸（标签 0）：

![16](./media/16.png)

戴口罩人脸 （标签 200）：

![17](./media/17.png)

存储的人脸（标签 1-15）

![18](./media/18.png)

---------------

## 4.7.3 保存人脸数据

开启人脸识别算法后，将摄像头正对人脸，按下功能按键约5秒后松开，Sengo2开始训练人脸，图像中当前的人脸数据会被存储并分配一个ID编号。

人脸数据的编号即标签值的分配原则：当前可用编号中最小的号。如果无空余编号，则Sengo2会提示保存失败。

----------------

## 4.7.4 删除人脸数据

执行完毕人脸存储操作后，按下功能按键约10秒后松开，即可删除刚存储的人脸数据；再次按下10秒后，则会清空存储的全部人脸数据。若算法开启后未执行过人脸保存操作，则下功能按键10秒后会直接清空全部的人脸数据。

------------------

## 4.7.5 返回数据

主控器获取识别结果时，算法会返回以下数据：

|     结果     |      含义       |
| :----------: | :-------------: |
|   kXValue    | 人脸中心横坐标x |
|   kYValue    | 人脸中心纵坐标y |
| kWidthValue  |    人脸宽度w    |
| kHeightValue |    人脸高度h    |
|    kLabel    |  人脸分类标签   |

代码：

```c
    // 遍历所有检测到的人脸
    for (int i = 1; i <= face_count; ++i) {
      // 获取人脸在图像中的位置和尺寸信息
      int face_x = sengo.GetValue(VISION_TYPE, kXValue, i);      // 人脸区域中心X坐标
      int face_y = sengo.GetValue(VISION_TYPE, kYValue, i);      // 人脸区域中心Y坐标
      int face_width = sengo.GetValue(VISION_TYPE, kWidthValue, i);  // 人脸区域宽度
      int face_height = sengo.GetValue(VISION_TYPE, kHeightValue, i); // 人脸区域高度
      
      // 获取人脸标签（在人脸检测中通常表示人脸ID，用于追踪不同的人）
      int face_id = sengo.GetValue(VISION_TYPE, kLabel, i);
      
      // 打印人脸详细信息
      Serial.print("  Face #");
      Serial.print(i);
      Serial.print(": ");
      Serial.print("Position=(");
      Serial.print(face_x);
      Serial.print(",");
      Serial.print(face_y);
      Serial.print("), Size=");
      Serial.print(face_width);
      Serial.print("x");
      Serial.print(face_height);
      Serial.print(", ID=");
      Serial.println(face_id);
      
    }
```

---------------

## 4.7.6 使用技巧

1. 环境光线充足，正对人脸且完整的人脸在视野中较大时识别效果佳
2. 佩戴眼镜或头发遮住面部时，会影响人脸检测效果

----------------

## 4.7.7 代码

```c
#include <Arduino.h>          // Arduino核心库
#include <Sentry.h>           // Sentry机器视觉传感器库

// 为Sengo2类型创建别名"Sengo"，简化后续使用
typedef Sengo2 Sengo;

// 定义通信方式（当前启用I2C）
#define SENGO_I2C             
// #define SENGO_UART          // UART串口通信方案（已注释禁用）

// 根据选择的通信方式包含相应库
#ifdef SENGO_I2C
#include <Wire.h>             // I2C通信所需库
#endif

#ifdef SENGO_UART
#include <SoftwareSerial.h>   // 软串口库
#define TX_PIN 11             // 自定义TX引脚号
#define RX_PIN 10             // 自定义RX引脚号
SoftwareSerial mySerial(RX_PIN, TX_PIN);  // 创建软串口对象
#endif

// 定义视觉处理类型为人脸检测模式
#define VISION_TYPE Sengo::kVisionFace  

// 创建Sengo传感器对象实例
Sengo sengo;

void setup() {
  sentry_err_t err = SENTRY_OK;  // 定义错误状态变量，初始化为无错误

  Serial.begin(9600);            // 初始化串口通信，波特率9600
  Serial.println("Waiting for sengo initialize...");  // 打印初始化提示

// 根据选择的通信方式初始化传感器
#ifdef SENGO_I2C
  Wire.begin();                   // 初始化I2C总线
  // 循环尝试连接传感器，直到成功
  // yield()函数在等待期间允许ESP8266/ESP32处理后台任务
  while (SENTRY_OK != sengo.begin(&Wire)) { 
    yield();  
  }
#endif  // SENGO_I2C

#ifdef SENGO_UART
  mySerial.begin(9600);           // 初始化软串口，波特率9600
  // 循环尝试连接传感器，直到成功
  while (SENTRY_OK != sengo.begin(&mySerial)) { 
    yield();  
  }
#endif  // SENGO_UART

  Serial.println("Sengo begin Success.");  // 打印传感器初始化成功信息
  
  // 启动人脸检测功能
  err = sengo.VisionBegin(VISION_TYPE);
  
  // 打印人脸检测初始化结果
  Serial.print("sengo.VisionBegin(kVisionFace) ");
  if (err) {
    Serial.print("Error: 0x");    // 如果出错，打印错误前缀
  } else {
    Serial.print("Success: 0x");  // 如果成功，打印成功前缀
  }
  Serial.println(err, HEX);       // 以16进制格式打印错误代码
  
  // 注意：这里没有额外的配置，使用默认人脸检测参数
  // 可选：设置最小人脸尺寸、检测角度等参数
}

void loop() {
  // 获取检测到的人脸数量（kStatus参数返回检测到的人脸总数）
  int face_count = sengo.GetValue(VISION_TYPE, kStatus);
  
  // 如果检测到至少一个人脸
  if (face_count > 0) {
    // 打印检测到的人脸总数
    Serial.print("Totally ");
    Serial.print(face_count);
    Serial.println(" faces detected");
    
    // 遍历所有检测到的人脸
    for (int i = 1; i <= face_count; ++i) {
      // 获取人脸在图像中的位置和尺寸信息
      int face_x = sengo.GetValue(VISION_TYPE, kXValue, i);      // 人脸区域中心X坐标
      int face_y = sengo.GetValue(VISION_TYPE, kYValue, i);      // 人脸区域中心Y坐标
      int face_width = sengo.GetValue(VISION_TYPE, kWidthValue, i);  // 人脸区域宽度
      int face_height = sengo.GetValue(VISION_TYPE, kHeightValue, i); // 人脸区域高度
      
      // 获取人脸标签（在人脸检测中通常表示人脸ID，用于追踪不同的人）
      int face_id = sengo.GetValue(VISION_TYPE, kLabel, i);
      
      // 打印人脸详细信息
      Serial.print("  Face #");
      Serial.print(i);
      Serial.print(": ");
      Serial.print("Position=(");
      Serial.print(face_x);
      Serial.print(",");
      Serial.print(face_y);
      Serial.print("), Size=");
      Serial.print(face_width);
      Serial.print("x");
      Serial.print(face_height);
      Serial.print(", ID=");
      Serial.println(face_id);
      
    }
  }
  
  delay(200);
}
```

--------------------

## 4.7.8 代码结果

上传代码后，按住AI视觉模块后面的功能按键并保持5秒然后对准人脸等待一会学习完毕后就可以对物体进行识别了，当遇到新的人脸与戴口罩的人脸也是会提示的。

![18](./media/18.png)

![31](./media/31.png)

## 4.7.9 扩展玩法

**专注力监测仪**

- **玩法简介：** 学习时，摄像头对着你。如果它检测到你的人脸离开了摄像头视野（扭头干别的去了），会发出友好的语音提醒：“嘀嘀嘀！”
- **实现：** 编程持续检测人脸。如果连续若干帧没有检测到人脸，则通过连接的语音模块触发提醒音频。

